package com.ruoyi.flowable.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.flowable.domain.FormData;
import com.ruoyi.flowable.domain.FormField;
import com.ruoyi.flowable.domain.FormVersion;
import com.ruoyi.flowable.domain.bo.FormDataBo;
import com.ruoyi.flowable.domain.vo.FormDataVo;
import com.ruoyi.flowable.mapper.FormDataMapper;
import com.ruoyi.flowable.mapper.FormVersionMapper;
import com.ruoyi.flowable.service.IFormDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 单提交数据Service业务层处理
 *
 * @author zxw
 * @date 2023-03-28
 */
@RequiredArgsConstructor
@Service
public class FormDataServiceImpl implements IFormDataService {

    private final FormDataMapper baseMapper;
    private final FormVersionMapper formVersionMapper;

    /**
     * 查询单提交数据
     */
    @Override
    public FormDataVo queryById(Long dataId){
        return baseMapper.selectVoById(dataId);
    }

    /**
     * 查询单提交数据列表
     */
    @Override
    public TableDataInfo<FormDataVo> queryPageList(FormDataBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<FormData> lqw = buildQueryWrapper(bo);
        Page<FormDataVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询单提交数据列表
     */
    @Override
    public List<FormDataVo> queryList(FormDataBo bo) {
        LambdaQueryWrapper<FormData> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<FormData> buildQueryWrapper(FormDataBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<FormData> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getUserName()), FormData::getUserName, bo.getUserName());
        lqw.eq(bo.getProcInstId() != null, FormData::getProcInstId, bo.getProcInstId());
        lqw.eq(bo.getAppVersionId() != null, FormData::getAppVersionId, bo.getAppVersionId());
        lqw.eq(bo.getFormVersionId() != null, FormData::getFormVersionId, bo.getFormVersionId());
        lqw.eq(StringUtils.isNotBlank(bo.getSubmitData()), FormData::getSubmitData, bo.getSubmitData());
        return lqw;
    }

    /**
     * 新增单提交数据
     */
    @Override
    public Boolean insertByBo(FormDataBo bo) {
        FormData add = BeanUtil.toBean(bo, FormData.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setDataId(add.getDataId());
        }
        return flag;
    }

    /**
     * 修改单提交数据
     */
    @Override
    public Boolean updateByBo(FormDataBo bo) {
        FormData update = BeanUtil.toBean(bo, FormData.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(FormData entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除单提交数据
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public FormDataVo selectFormDataByInstId(String procInstId) {
        LambdaQueryWrapper<FormData> lqw = Wrappers.lambdaQuery();
        lqw.eq(FormData::getProcInstId, procInstId);
        lqw.last("limit 1");
        return baseMapper.selectVoOne(lqw);
    }



    @Override
    @Async
    public void asyncSaveData(FormDataBo formData) throws IOException {
        FormVersion formVersion = formVersionMapper.selectById(formData.getFormVersionId());
        if (formVersion == null) {
            throw new ServiceException("表单版本不存在");
        }

        Map<String, Object> dataJson = JsonUtils.parseObject(formData.getSubmitData(), Map.class);
        List<FormField> formFields = JsonUtils.parseArray(formVersion.getFormField(), FormField.class);
        List<FormField> subFormFields = JsonUtils.parseArray(formVersion.getSubFormField(), FormField.class);


        Map<String, List<Map<String, Object>>> optionMap = new HashMap<>();
        formFields.forEach(item -> {
            if (null != item.getOptionItems() && !item.getOptionItems().isEmpty()) {
                optionMap.put(item.getName(), item.getOptionItems());
            }
        });

        //处理主表和子表字段
        Map<String, List<FormField>> subForms = new HashMap<>();
        if (!subFormFields.isEmpty()) {
            //从所有字段中去掉重复表字段,以及按照子表分组字段
            Map<String, String> excludeFeild = new HashMap<>();
            for (FormField field : subFormFields) {
                excludeFeild.put(field.getName(), field.getType());
                if (subForms.containsKey(field.getSubForm())) {
                    subForms.get(field.getSubForm()).add(field);
                } else {
                    List<FormField> list = new ArrayList<>();
                    list.add(field);
                    subForms.put(field.getSubForm(), list);
                }
            }
            //从所有字段中去掉子表字段
            formFields.removeIf(field -> excludeFeild.containsKey(field.getName()));
        }

        //1.检查表是否存在，如果存在，检查字段是否一致，如果不存在，建表
        //2.字段一致或者填报字段都存在，则写入数据库，如果有字段不存在，先执行alter语句再写入
        String tableName = "form_" + formVersion.getFormId();
        int isExist = baseMapper.tableExist(tableName);
        if (isExist == 1) { //表存在
            //主表字段添加
            cloumnChange(formFields, tableName);
            //子表字段添加
            subForms.forEach((key, item) -> {
                int subExist = baseMapper.tableExist(tableName + "_" + key);
                if (subExist == 0) {
                    baseMapper.createSubTable(tableName + "_" + key, item);
                } else {
                    cloumnChange(item, tableName + "_" + key);
                }
            });

            saveData(dataJson, tableName, formData, optionMap);
        } else { //表不存在，建表

            //创建主表
            baseMapper.createMainTable(tableName, formFields);
            //创建子表
            subForms.forEach((key, item) -> {
                int subExist = baseMapper.tableExist(tableName + "_" + key);
                if (subExist == 0) baseMapper.createSubTable(tableName + "_" + key, item);
            });
            //保存数据
            saveData(dataJson, tableName, formData, optionMap);
        }
    }

    //判断是否增加
    private void cloumnChange(List<FormField> formFields, String tableName) {
        List<FormField> tableField = baseMapper.getTableColumn(tableName);
        Map<String, String> collect = tableField.stream().collect(Collectors.toMap(FormField::getName, FormField::getType));
        formFields.forEach(item -> {
            //如果不存在，说明是新加字段，只添加字段，不删除字段
            if (!collect.containsKey(item.getName())) {
                baseMapper.addColumn(tableName, item);
            }
        });
    }

    //保存数据
    private void saveData(Map<String, Object> dataJson, String tableName, FormDataBo formData, Map<String, List<Map<String, Object>>> optionMap) throws JsonProcessingException {
        //写入数据
        Map<String, Object> mainData = new HashMap<>(); //主数据
        Map<String, List<Map<String, Object>>> subData = new HashMap(); //子表数据
        for (String key : dataJson.keySet()) {
            if (key.contains("subform") || key.contains("gridsubform")) {
                subData.put(key, (List<Map<String, Object>>) dataJson.get(key));
            } else {
                Object obj = dataJson.get(key);
                if (optionMap.containsKey(key)) {
                    obj = getOptionLabel(obj, optionMap.get(key));
                }
                mainData.put(key, obj);
            }
        }
        mainData.put("data_id", formData.getDataId());
        int dataExist = baseMapper.dataExist(tableName, formData.getDataId());
        if (dataExist == 1){
            mainData.put("update_time", DateUtils.getTime());
            baseMapper.updateMapData(tableName, mainData);
        } else {
            mainData.put("user_name", formData.getUserName());
            mainData.put("proc_inst_id", formData.getProcInstId());
            mainData.put("app_version_id", formData.getAppVersionId());
            mainData.put("form_version_id", formData.getFormVersionId());
            mainData.put("inst_status", "进行中");
            mainData.put("create_time", DateUtils.getTime());
            baseMapper.insertMapData(tableName, mainData);
        }

        subData.forEach((key, list) -> {
            if (dataExist == 1) baseMapper.deleteMapData(tableName + "_" + key, formData.getDataId()); //重复表可能删除行，所以直接删除重新添加
            list.forEach(item -> {
                item.forEach((k, v) -> {
                    if (optionMap.containsKey(k)) {
                        item.put(k, getOptionLabel(v, optionMap.get(k)));
                    }
                });
                item.put("id", IdUtil.getSnowflakeNextId());
                item.put("data_id", formData.getDataId());
                baseMapper.insertMapData(tableName + "_" + key, item);
            });
        });
    }

    //字典转换value为label
    private Object getOptionLabel(Object value, List<Map<String, Object>> items) {
        Map<Object, Object> map = new HashMap<>();
        items.forEach(item -> {
            map.put(item.get("value").toString(), item.get("label"));
        });
        if (map.containsKey(value.toString())) {
            return map.get(value.toString());
        }
        return null;
    }


    @Override
    public int updateMapData(String tableName, Map<String, Object> formData) {
        return baseMapper.updateMapData(tableName, formData);
    }

    @Override
    public int deleteMapData(String tableName, Long dataId) {
        return baseMapper.deleteMapData(tableName, dataId);
    }

}
